/*   Copyright (C) 2008  Jeroen v. Schagen & Youri Lima
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;

using Engine;
using Engine.Connection;
using Engine.Connection.Server;

namespace LoginServer
{
    public partial class LoginServerForm : Form
    {
        private TCPServer server;

        public LoginServerForm()
        {
            InitializeComponent();

            // Initiate server
            server = new TCPServer("Login");

            // Attach events
            server.ClientConnect += new ClientEventHandler(server_ClientConnect);
            server.ClientDisconnect += new ClientEventHandler(server_ClientDisconnect);
            server.DataRecieved += new PackageEventHandler(server_DataRecieved);
        }

        public static void Main()
        {
            // Configure logger
            Engine.Logger.Configure("data/config/log4net.cfg.xml");

            // Run application
            Application.Run(new LoginServerForm());
        }

        // Server callbacks
        private void server_ClientConnect(object sender, User client)
        {
            Console.WriteLine("Connected: " + client);
        }

        private void server_ClientDisconnect(object sender, User client)
        {
            Console.WriteLine("Disconnected: " + client);
        }

        private void server_DataRecieved(object sender, Packet package)
        {
            // Decode package
            byte[] buffer = package.DataBuffer;
            char[] chars = new char[buffer.Length];

            Decoder d = Encoding.ASCII.GetDecoder();
            d.GetChars(buffer, 0, buffer.Length, chars, 0);

            String data = new String(chars);

            try
            {
                // Request login
                if (data.StartsWith("/rl"))
                {
                    String[] split = data.Split(' ');

                    if (split.Length == 3)
                    {
                        // Retrieve given parameters
                        String username = split[1];
                        String password = split[2];

                        // Retrieve account information
                        Domain.Account account = Database.ObjectManager<Domain.Account>.Get(username);

                        if (account != null)
                        {
                            // Compare parameters to data
                            if (password == account.Password)
                            {
                                // Send succes
                                String message = "/sl " + account.Username + " " + account.Email;

                                foreach (Domain.Player p in account.Players)
                                {
                                    message += " " + p.Name;
                                }

                                server.Send(Encoding.ASCII.GetBytes(message), package.User);

                                // Link socket to account
                                package.User.Object = account;
                            }

                            else
                            {
                                // Invalid password
                                String message = "/fl Invalid password";
                                server.Send(Encoding.ASCII.GetBytes(message), package.User);
                            }
                        }

                        else
                        {
                            // Invalid user
                            String message = "/fl Invalid account";
                            server.Send(Encoding.ASCII.GetBytes(message), package.User);
                        }
                    }

                    else
                    {
                        // Invalid paremters
                        String message = String.Format("'{0}' is not a valid command.", data);
                        server.Send(Encoding.ASCII.GetBytes(message), package.User);
                    }
                }

                // Request logg out
                else if (data.StartsWith("/rlo"))
                {
                    package.User.Object = null;
                }

                // Request password change
                else if (data.StartsWith("/rpc"))
                {
                    String[] split = data.Split(' ');

                    if (split.Length == 2)
                    {
                        String password = split[1];
                        Domain.Account account = (Domain.Account)package.User.Object;

                        // Validate user
                        if (account != null)
                        {
                            // Change password
                            account.Password = password;

                            // Update in database
                            if (Database.ObjectManager<Domain.Account>.Update(account))
                            {
                                // Send succes
                                String message = "/spc";
                                server.Send(Encoding.ASCII.GetBytes(message), package.User);
                            }

                            else
                            {
                                // Database error
                                String message = "/fpc Database error";
                                server.Send(Encoding.ASCII.GetBytes(message), package.User);
                            }
                        }

                        else
                        {
                            // Account error
                            String message = "/fpc Account error";
                            server.Send(Encoding.ASCII.GetBytes(message), package.User);
                        }
                    }

                    else
                    {
                        // Invalid parameters
                        String message = String.Format("'{0}' is not a valid command.", data);
                        server.Send(Encoding.ASCII.GetBytes(message), package.User);
                    }
                }

                // Request account information
                else if (data.StartsWith("/rai"))
                {
                    String[] split = data.Split(' ');

                    if (split.Length == 2)
                    {
                        String username = split[1];

                        // Retrieve account information
                        Domain.Account account = Database.ObjectManager<Domain.Account>.Get(username);

                        if (account != null)
                        {
                            String message = "/sai " + account.Username + " " + account.Email;

                            foreach (Domain.Player p in account.Players)
                            {
                                message += " " + p.Name;
                            }

                            server.Send(Encoding.ASCII.GetBytes(message), package.User);
                        }
                    }
                }

                // Request players information
                else if (data.StartsWith("/rpi"))
                {
                    String[] split = data.Split(' ');

                    if (split.Length == 2)
                    {
                        String name = split[1];

                        // Retrieve account information
                        Domain.Player player = Database.ObjectManager<Domain.Player>.Get(name);

                        if (player != null)
                        {
                            String message = "/spi " + player.Name + " " + player.Health + " " + player.X + " " + player.Y + " " + player.Z;
                            server.Send(Encoding.ASCII.GetBytes(message), package.User);
                        }
                    }
                }

                // Invalid command
                else
                {
                    String message = String.Format("'{0}' is not a valid command.", data);
                    server.Send(Encoding.ASCII.GetBytes(message), package.User);
                }
            }

            // Process exception
            catch (Exception e)
            {
                // Display script
                Console.WriteLine("Exception occured while proccesing script '" + data + "'.");

                // Display exception
                Console.WriteLine(e);
            }
        }

        // Form callbacks
        private void startToolStripMenuItem_Click(object sender, EventArgs e)
        {
            server.Listen(Int32.Parse(txfPort.Text));
        }

        private void rebootToolStripMenuItem_Click(object sender, EventArgs e)
        {
            server.Close();
            server.Listen(Int32.Parse(txfPort.Text));
        }

        private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            server.Close();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnBroadcast_Click(object sender, EventArgs e)
        {
            if (txfMessage.Text != "")
            {
                server.Send(Encoding.ASCII.GetBytes(txfMessage.Text));

                txfMessage.Text = "";
                txfMessage.Focus();
            }
        }
    }
}